package com.ndp.fb.walle.business.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.ndp.fb.constant.CommonConstants;
import com.ndp.fb.enums.search.DemographicType;
import com.ndp.fb.fbagent.service.SerchFBService;
import com.ndp.fb.model.fbagent.param.serach.SearchParam;
import com.ndp.fb.model.fbagent.result.common.FBAdGeolocation;
import com.ndp.fb.model.fbagent.result.common.FBAdInterest;
import com.ndp.fb.model.fbagent.result.common.FBSearchCategoryResult;
import com.ndp.fb.model.fbagent.result.common.FBSearchResult;
import com.ndp.fb.mongo.api.TargetingService;
import com.ndp.fb.rdb.api.DictionaryRdbService;
import com.ndp.fb.rdb.api.GeolocationRdbService;
import com.ndp.fb.rdb.model.AdGeolocation;
import com.ndp.fb.rdb.model.Dictionary;
import com.ndp.fb.rdb.model.InterestWord;
import com.ndp.fb.walle.business.SearchService;
import com.ndp.fb.walle.model.bo.search.result.AdGeolocationBo;
import com.ndp.fb.walle.model.bo.search.result.MoreTargetingCategoryBo;
import com.ndp.fb.walle.model.bo.search.result.MoreTargetingCategoryResultBo;
import com.ndp.fb.walle.model.vo.search.result.TargetingCategoryParentVo;
import com.ndp.fb.walle.model.vo.search.result.TargetingCategoryVo;
import com.ndp.fb.walle.util.ConversionUtils;

/**
 * Created by Sisi on 14-10-27.
 */
@Component
public class SearchServiceImpl implements SearchService {
    private final org.slf4j.Logger LOG = LoggerFactory.getLogger(getClass());

    @Reference
    private SerchFBService searchHelper;

    @Reference
    private GeolocationRdbService geolocationRdbService;

    @Reference
    private DictionaryRdbService dictionaryRdbService;
    
    @Reference
    private TargetingService targetingService;

    @Override
    public List<Dictionary> getDict(String type) {
        return dictionaryRdbService.getDict(type);
    }

    @Override
    public List<Dictionary> getDict(String type, String language) {
        if ("zh-cn".equals(language) || "zh_CN".equals(language) || "zh".equals(language) || "CN".equals(language)) {
            return dictionaryRdbService.getDict(type);
        } else  {
            return dictionaryRdbService.getDictEN(type);
        }
    }

    @Override
    public List<?> search(SearchParam searchParam) {
        try {
            return searchHelper.search(searchParam);
        } catch (Exception e) {
            LOG.error("SearchServiceImpl->search->", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<?> search(String accessToken, String locale, String q, String type) {
        try {
            return searchHelper.search(accessToken, locale, q, type);
        } catch (Exception e) {
            LOG.error("SearchServiceImpl->search->", e);
            return Collections.emptyList();
        }
    }


    private List<AdGeolocationBo> fBAdGeolocationToBo(List<FBAdGeolocation> fBAdGeolocationes) {
        List<AdGeolocationBo> adGeolocationBoes = new ArrayList<>();
        AdGeolocationBo adGeolocationBo;
        for (FBAdGeolocation fBAdGeolocation : fBAdGeolocationes) {
            adGeolocationBo = new AdGeolocationBo();
            ConversionUtils.conversion(fBAdGeolocation, adGeolocationBo);
            adGeolocationBoes.add(adGeolocationBo);
        }
        return adGeolocationBoes;
    }

    @Override
    public List<FBAdInterest> searchInterestList(String accessToken, String locale, String q, List<String> interestList) {
        try {
            //1、查询FB数据
            List<FBAdInterest> data = searchHelper.searchInterestList(accessToken, locale, q, interestList);
            //2、去除无效的数据
            List<FBAdInterest> validData = new ArrayList<>();
            for (FBAdInterest interest : data) {
                if (interest.getValid()) {
                    validData.add(interest);
                }
            }
            return validData;
        } catch (Exception e) {
            LOG.error("SearchServiceImpl->searchInterestList->", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<FBAdInterest> searchInterestSuggestion(String accessToken, String locale, List<String> interestsList) {
        SearchParam searchParam = new SearchParam();
        searchParam.setType("adinterestsuggestion");
        searchParam.setLocale(locale);
        searchParam.setLimit(CommonConstants.NUM_INT_10);
        searchParam.setAccessToken(accessToken);
        searchParam.setInterestList(interestsList);
        try {
            return searchHelper.search(searchParam, FBAdInterest.class);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<TargetingCategoryParentVo> searchInterestsCategory(String accessToken, String locale) {
        List<TargetingCategoryParentVo> interestCategories = new ArrayList<>();
        try {
            SearchParam searchParam = new SearchParam();
            searchParam.setType("adTargetingCategory");
            searchParam.setClassT("interests");
            searchParam.setLocale(locale);
            searchParam.setAccessToken(accessToken);
            List<FBSearchCategoryResult> fBSearchCategoryResults = searchHelper.search(searchParam, FBSearchCategoryResult.class);
            if (!CollectionUtils.isEmpty(fBSearchCategoryResults)){
                interestCategories =  buildInterestCategory(fBSearchCategoryResults);
            }
        } catch (Exception e){
            LOG.error(e.getMessage(), e);
        }
        return interestCategories;
    }

    public List<TargetingCategoryParentVo> buildInterestCategory(List<FBSearchCategoryResult> fBSearchCategoryResults) {
        Map<String, TargetingCategoryParentVo> interestCategoryMap = new HashMap<>();
        List<String> path;
        String name;
        TargetingCategoryParentVo targetingCategoryParentVo;
        for (FBSearchCategoryResult fBSearchCategoryResult : fBSearchCategoryResults){
            path = fBSearchCategoryResult.getPath();
            name = fBSearchCategoryResult.getName();
            //创建节点
            targetingCategoryParentVo = interestCategoryMap.get(name);
            if (null == targetingCategoryParentVo){
                targetingCategoryParentVo = new TargetingCategoryParentVo();
                interestCategoryMap.put(name, targetingCategoryParentVo);
            }

            targetingCategoryParentVo.setId(fBSearchCategoryResult.getId());
            targetingCategoryParentVo.setName(name);
            targetingCategoryParentVo.setAudienceSize(fBSearchCategoryResult.getAudienceSize());

            //构造父子关系
            TargetingCategoryParentVo parentC = null;
            TargetingCategoryParentVo nodeC;
            boolean isNewSon;
            for (String node : path){
                nodeC = interestCategoryMap.get(node);
                isNewSon = null == nodeC || null == nodeC.getParentName();
                if (null == nodeC){
                    nodeC = new TargetingCategoryParentVo();
                    nodeC.setName(node);
                    interestCategoryMap.put(node, nodeC);
                }

                if (null != parentC && isNewSon) {
                    //如果是子 则构造子元素
                    if (null == parentC.getSon()){
                        parentC.setSon(new ArrayList<TargetingCategoryVo>());
                    }

                    parentC.getSon().add(nodeC);

                    nodeC.setParentName(parentC.getName());
                }
                parentC = nodeC;
            }
        }

        List<TargetingCategoryParentVo>  interestCategories = new ArrayList<>();
        for (Map.Entry<String, TargetingCategoryParentVo> temp: interestCategoryMap.entrySet()){
             if (null != temp.getValue() && null == temp.getValue().getParentName()){
                 interestCategories.add(temp.getValue());
             }
        }

        return interestCategories;
    }

    @Override
    public List<InterestWord> adInterestValid(String accessToken, List<InterestWord> interestWords) {
        List<InterestWord> results = new ArrayList<>();
        if (!CollectionUtils.isEmpty(interestWords)){
            List<Long> ids = new ArrayList<>();
            Map<Long, InterestWord> map = new HashMap<>();
            for (InterestWord interestWord : interestWords){
                ids.add(interestWord.getId());
                map.put(interestWord.getId(), interestWord);
            }

            //根据兴趣词id校验兴趣词的有效性  只返回有效的
            List<FBAdInterest> fbAdInterestList = searchHelper.searchInterestListForValid(accessToken, ids);
            if (!CollectionUtils.isEmpty(fbAdInterestList)){
                InterestWord interestWord;
                for (FBAdInterest fBAdInterest : fbAdInterestList){
                    interestWord = map.get(fBAdInterest.getId());
                    if (null == interestWord || null == fBAdInterest.getValid() || !fBAdInterest.getValid()){
                        continue;
                    }
                    interestWord.setValid(true);
                    results.add(interestWord);
                }
            }
        }
        return results;
    }

    @Override
    public List<AdGeolocationBo> searchCountryAndCity(String accessToken, String locale, String q, String cType) {
        try {
            List<AdGeolocationBo> returnList = new ArrayList<>();
            if ("city".equals(cType)) {
                List<FBAdGeolocation> fBAdGeolocation = searchHelper.searchCitys(accessToken, locale, q);
                returnList = fBAdGeolocationToBo(fBAdGeolocation);
            } else if ("country".equals(cType)) {
                List<AdGeolocation> list = targetingService.getCountryByNameCode(q, locale);//geolocationRdbService.searchListByKey(q);
                returnList = rdbAdGeolocationToBo(list);
            }else if ("all".equals(cType)) {
            	List<FBAdGeolocation> fBAdGeolocation = searchHelper.searchAllGeolocation(accessToken, locale, q);
                returnList = fBAdGeolocationToBo(fBAdGeolocation);
            }
            return returnList;
        } catch (Exception e) {
            LOG.error("SearchServiceImpl->searchCountryAndCity-> accessToken >>> {},locale>>>{},q>>>{}", accessToken, locale, q);
            LOG.error("SearchServiceImpl->searchCountryAndCity->", e);
            return Collections.emptyList();
        }
    }

    public List<AdGeolocation> searchALLCountry(){
        return geolocationRdbService.getAll();
    }

    @Override
    public List<AdGeolocationBo> searchCountryListByCodes(String countries) {
        try {
            List<AdGeolocation> list = geolocationRdbService.searchListByKeys(countries);
            //2、转为BO
            return rdbAdGeolocationToBo(list);
        } catch (Exception e) {
            LOG.error("SearchServiceImpl->searchCountryListByCodes->", e);
            return Collections.emptyList();
        }
    }

    private List<AdGeolocationBo> rdbAdGeolocationToBo(List<AdGeolocation> adGeolocationes) {
        List<AdGeolocationBo> adGeolocationBoes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(adGeolocationes)) {
            AdGeolocationBo adGeolocationBo;
            for (AdGeolocation adGeolocation : adGeolocationes) {
                adGeolocationBo = new AdGeolocationBo();
                ConversionUtils.conversion(adGeolocation, adGeolocationBo);
                adGeolocationBoes.add(adGeolocationBo);
            }
        }
        return adGeolocationBoes;
    }

    @Override
    public List<FBSearchResult> searchByQ(String accessToken, String locale, String q, String type) {
        SearchParam searchParam = new SearchParam();
        searchParam.setLocale(locale);
        searchParam.setType(type);
        searchParam.setQ(q);
        searchParam.setLimit(CommonConstants.NUM_INT_500);
        searchParam.setAccessToken(accessToken);
        try {
            return searchHelper.search(searchParam, FBSearchResult.class);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return Collections.emptyList();
        }
    }

    @Override
    public MoreTargetingCategoryResultBo searchMoreTargetingCategory(String accessToken, String locale) {
        //FB查询Demographic
        List<FBSearchCategoryResult> demographicCategories = searchDemographicCategories(accessToken, locale);

        //根据查询结果 转换
        MoreTargetingCategoryBo moreTargetingCategoryBo = new MoreTargetingCategoryBo(
                new HashMap(),
                new HashMap(),
                new HashMap(),
                new HashMap(),
                new HashMap(),
                new HashMap());
        for (FBSearchCategoryResult fBSearchCategoryResult : demographicCategories) {
            String type = fBSearchCategoryResult.getType();
            DemographicType demographicType = DemographicType.getDemographicType(type);
            if (null == demographicType){
                continue;
            }

            Map<String, TargetingCategoryParentVo> targetingCategoryVos = getTargetingCategoryParentsByType(moreTargetingCategoryBo, demographicType);

            if (null == targetingCategoryVos) {
                continue;
            }

            //构造类别之间的层级关系--最多两级
            buildCategoryLevels(fBSearchCategoryResult, targetingCategoryVos);
        }

        MoreTargetingCategoryResultBo moreTargetingCategoryResultBo = new MoreTargetingCategoryResultBo();
        moreTargetingCategoryResultBo.setIndustries(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getIndustries()));
        moreTargetingCategoryResultBo.setEthnicAffinity(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getEthnicAffinity()));
        moreTargetingCategoryResultBo.setGeneration(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getGeneration()));
        moreTargetingCategoryResultBo.setFamilyStatuses(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getFamilyStatuses()));
        moreTargetingCategoryResultBo.setPolitics(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getPolitics()));
        moreTargetingCategoryResultBo.setLifeEvents(buildMoreTargetingCategoryResult(moreTargetingCategoryBo.getLifeEvents()));

        return moreTargetingCategoryResultBo;
    }

    private void buildCategoryLevels(FBSearchCategoryResult fBSearchCategoryResult, Map<String, TargetingCategoryParentVo> targetingCategoryVos) {
        //获取path 即类别之间的层级关系
        List<String> path = fBSearchCategoryResult.getPath();

        if (CollectionUtils.isEmpty(path) || CommonConstants.NUM_INT_1 == path.size()){
            //如果path只有一个或没有 即无子 直接put
            TargetingCategoryParentVo targetingCategoryParentVo = targetingCategoryVos.get(fBSearchCategoryResult.getName());
            if (null == targetingCategoryParentVo){
                targetingCategoryParentVo = new TargetingCategoryParentVo();
                targetingCategoryVos.put(fBSearchCategoryResult.getName(), targetingCategoryParentVo);
            }

            targetingCategoryParentVo.setId(fBSearchCategoryResult.getId());
            targetingCategoryParentVo.setName(fBSearchCategoryResult.getName());
            targetingCategoryParentVo.setAudienceSize(fBSearchCategoryResult.getAudienceSize());
            targetingCategoryParentVo.setDescription(fBSearchCategoryResult.getDescription());
        } else {
            //如果path>1 第一个为 父  最后一个为子（将多层级转为两级）
            //先找到父
            String parentName = path.get(0);
            TargetingCategoryParentVo targetingCategoryParentVo = targetingCategoryVos.get(parentName);
            if (null == targetingCategoryParentVo){
                targetingCategoryParentVo = new TargetingCategoryParentVo();
                targetingCategoryVos.put(parentName, targetingCategoryParentVo);
            }

            targetingCategoryParentVo.setName(parentName);

            // 再构造子
            List<TargetingCategoryVo> sons = targetingCategoryParentVo.getSon();
            if (null == sons){
                sons = new ArrayList<>();
                targetingCategoryParentVo.setSon(sons);
            }

            TargetingCategoryVo son = new TargetingCategoryVo();
            son.setId(fBSearchCategoryResult.getId());
            son.setName(fBSearchCategoryResult.getName());
            son.setAudienceSize(fBSearchCategoryResult.getAudienceSize());
            son.setDescription(fBSearchCategoryResult.getDescription());
            son.setParentName(parentName);
            sons.add(son);
        }
    }

    private Map<String, TargetingCategoryParentVo> getTargetingCategoryParentsByType(
            MoreTargetingCategoryBo moreTargetingCategoryBo, DemographicType demographicType) {
        Map<String, TargetingCategoryParentVo> targetingCategoryVos = null;
        switch (demographicType) {
            case industries:
                targetingCategoryVos = moreTargetingCategoryBo.getIndustries();
                break;
            case ethnic_affinity:
                targetingCategoryVos = moreTargetingCategoryBo.getEthnicAffinity();
                break;
            case generation:
                targetingCategoryVos = moreTargetingCategoryBo.getGeneration();
                break;
            case family_statuses:
                targetingCategoryVos = moreTargetingCategoryBo.getFamilyStatuses();
                break;
            case politics:
                targetingCategoryVos = moreTargetingCategoryBo.getPolitics();
                break;
            case life_events:
                targetingCategoryVos = moreTargetingCategoryBo.getLifeEvents();
                break;
            default:
                break;
        }
        return targetingCategoryVos;
    }

    private List<TargetingCategoryParentVo> buildMoreTargetingCategoryResult(Map<String, TargetingCategoryParentVo> industries) {
        if (CollectionUtils.isEmpty(industries)) {
            return Collections.emptyList();
        }

        return new ArrayList<>(industries.values());
    }

    private List<FBSearchCategoryResult> searchDemographicCategories(String accessToken, String locale) {
        SearchParam searchParam = new SearchParam();
        searchParam.setType("adTargetingCategory");
        searchParam.setClassT("demographics");
        searchParam.setLocale(locale);
        searchParam.setLimit(CommonConstants.NUM_INT_500);
        searchParam.setAccessToken(accessToken);
        try {
            return searchHelper.search(searchParam, FBSearchCategoryResult.class);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return Collections.emptyList();
        }
    }

	@Override
	public List<FBSearchCategoryResult> searchFbAdTargetingCategory(String accessToken, String locale, String className,
			String q) {
		SearchParam searchParam = new SearchParam();
		searchParam.setType("adTargetingCategory");
		searchParam.setClassT(className);
		searchParam.setLocale(locale);
		searchParam.setAccessToken(accessToken);
		searchParam.setQ(q);
		try {
			return searchHelper.search(searchParam, FBSearchCategoryResult.class);
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			return Collections.emptyList();
		}
	}

	@Override
	public List<JSONObject> getTargetingBrowse(String lan) {
		return targetingService.getTargetingBrowse(lan);
	}
}
